﻿using System;
using System.IO;
using System.Net;
using System.Security.Cryptography;

namespace Tools.Resource {

    /// <summary>
    /// [七牛]消息认证(Message Authentication)
    /// </summary>
    public class MessageAuther {

        private string _accessKey;

        /// <summary>
        /// Gets or sets the access key.
        /// </summary>
        /// <value>The access key.</value>
        public string AccessKey {
            get { return _accessKey; }
            set { _accessKey = value; }
        }

        private readonly byte[] _secretKey;

        /// <summary>
        /// Gets the secret key.
        /// </summary>
        /// <value>The secret key.</value>
        public byte[] SecretKey {
            get { return _secretKey; }
        }

        public MessageAuther() {
            _accessKey = Configer.AccessKey;
            _secretKey = Configer.Encoding.GetBytes(Configer.SecretKey);
        }

        public MessageAuther(string access, byte[] secretKey) {
            _accessKey = access;
            _secretKey = secretKey;
        }

        /// <summary>
        /// 根据SK初始化的HMACSHA1，来计算接收数据的哈希值，并base64编码
        /// </summary>
        /// <param name="data">TODO：什么数据</param>
        /// <returns>base64编码</returns>
        private string _sign(byte[] data) {
            HMACSHA1 hmac = new HMACSHA1(SecretKey);
            byte[] digest = hmac.ComputeHash(data);
            return Base64UrlSafe.Encode(digest);
        }

        /// <summary>
        /// Sign
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        public string Sign(byte[] b) {
            return string.Format("{0}:{1}", this._accessKey, _sign(b));
        }

        /// <summary>
        /// SignWithData
        /// </summary>
        /// <param name="b"></param>
        /// <returns></returns>
        public string SignWithData(byte[] b) {
            string data = Base64UrlSafe.Encode(b);
            return string.Format("{0}:{1}:{2}", this._accessKey, _sign(Configer.Encoding.GetBytes(data)), data);
        }

        /// <summary>
        /// SignRequest
        /// </summary>
        /// <param name="request"></param>
        /// <param name="body"></param>
        /// <returns></returns>
        public string SignRequest(HttpWebRequest request, byte[] body) {
            Uri u = request.Address;
            using (HMACSHA1 hmac = new HMACSHA1(_secretKey)) {
                string pathAndQuery = request.Address.PathAndQuery;
                byte[] pathAndQueryBytes = Configer.Encoding.GetBytes(pathAndQuery);
                using (MemoryStream buffer = new MemoryStream()) {
                    buffer.Write(pathAndQueryBytes, 0, pathAndQueryBytes.Length);
                    buffer.WriteByte((byte)'\n');
                    if (body.Length > 0) {
                        buffer.Write(body, 0, body.Length);
                    }
                    byte[] digest = hmac.ComputeHash(buffer.ToArray());
                    string digestBase64 = Base64UrlSafe.Encode(digest);
                    return this._accessKey + ":" + digestBase64;
                }
            }
        }
    }
}
